package org.deltaset.meta.internal;

import org.deltaset.meta.EntityResolver;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import static org.deltaset.meta.internal.MetaActionType.*;

/**
 *
 * @author dmakariev
 */
class Group {

    private final Set<MetaActionType> typeSet;
    private final String order;
    private final Class entityClass;
    private final Class executeClass;
    private final Method method;
    private final EntityResolver entityResolver;

    Group(final Set<MetaActionType> typeSet,
            String order,
            final Class entityClass,
            final Class executeClass,
            final Method method,
            final EntityResolver entityResolver) {
        this.typeSet = typeSet;
        this.order = order;
        this.entityClass = entityClass;
        this.executeClass = executeClass;
        this.method = method;
        this.entityResolver = entityResolver;        
    }

    public MetaActionImpl getMetaAction() {
        //final String methodName = method.getName();
        final int parameterCount = method.getParameterTypes().length;        
        final MetaParameter parameter = MetaClassFactory.extractMetaParameter(method, executeClass, entityResolver);

        final Method disableMethod = extractDisableMethod(method, entityClass);
        final Method hideMethod = extractHideMethod(method, entityClass);
       // final boolean isEnableWarn = methodName.startsWith("warn");

        final boolean isFactory = isFactory();
        final boolean isReturningEntity = isReturningEntity();
        final boolean isReturningVoid = isReturningVoid();
        final boolean hasParameter = hasParameter(parameterCount);
        final boolean isContext = isContext();
        final boolean isEntityMember = isEntityMember();
        final boolean isFinder = isFinder();

        final MetaActionImpl metaAction = new MetaActionImpl(entityClass, executeClass,  method, disableMethod, hideMethod, parameter, isFactory,isFinder, isReturningEntity, isReturningVoid, hasParameter, isContext, isEntityMember);

        return metaAction;
    }

    String getOrder() {
        return order;
    }

    boolean isEntityMember() {
        return typeIs(ENTITY_MEMBER) && typeIsNot(HELPER);
    }

    boolean isAcceptingEntity() {
        return typeIs(ACCEPT_ENTITY) && typeIsNot(HELPER);
    }

    boolean isReturningVoid() {
        return typeIs(RETURN_VOID) && typeIsNot(HELPER);
    }

    boolean isContext() {

//        if (metaAction.typeIsOr(ACCEPT_ENTITY, ENTITY_MEMBER)
//                    && metaAction.typeIsOr(RETURN_VOID, RETURN_ENTITY)
//                    && metaAction.typeIsNot(HELPER))

//typeIsOr(ACCEPT_ENTITY, ENTITY_MEMBER) && typeIsNot(HELPER)        

        //return typeIsOr(ACCEPT_ENTITY, ENTITY_MEMBER)&& typeIsOr(RETURN_VOID, RETURN_ENTITY) && typeIsNot(HELPER);
        return typeIsOr(ACCEPT_ENTITY, ENTITY_MEMBER) && typeIsNot(HELPER);
    }

    boolean hasParameter(final int parameterCount) {
        if (0 == parameterCount) {
            return false;
        }

        if (1 == parameterCount && typeIs(ACCEPT_ENTITY)) {
            return false;
        }

        if (2 == parameterCount && typeIs(PAGING)) {
            return false;
        }

        if (3 == parameterCount && typeIsAnd(PAGING, ACCEPT_ENTITY)) {
            return false;
        }

        return true;
    }

    boolean isReturningEntity() {
        return typeIs(RETURN_ENTITY) && typeIsNot(HELPER);
    }

    boolean isFactory() {
        return typeIsOr(FACTORY_METHOD, RETURN_ENTITY)
                && typeIsNot(ACCEPT_ENTITY, ByID, ENTITY_MEMBER, HELPER);
    }

    boolean isOther() {

        return !isFactory()
                && typeIsOr(RETURN_OBJECT, RETURN_VOID, RETURN_SIMPLE)
                && typeIsNot(ByID, FINDER, TITLE, HELPER, ACCEPT_ENTITY, ENTITY_MEMBER);
    }

    boolean isOtherContext() {
        return !isFactory()
                && typeIsOr(ACCEPT_ENTITY, ENTITY_MEMBER)
                && typeIsNot(RETURN_VOID, RETURN_ENTITY, TITLE, HELPER);
    }

    boolean isFinder() {
        return typeIsOr(FINDER, RETURN_ENTITY_COLLECTION)
                && typeIsNot(ENTITY_MEMBER, ACCEPT_ENTITY, ByID)
                && typeIsNot(HELPER);
    }

    boolean isDefaultFinder() {
        return typeIs(DEFAULT_FINDER);
    }

    boolean isFindById() {
        return typeIs(ByID);
    }

///////////////
    private boolean typeIs(final MetaActionType actionType) {
        return typeSet.contains(actionType);
    }

    private boolean typeIsNot(final MetaActionType actionType) {
        return false == typeSet.contains(actionType);
    }

    private boolean typeIsNot(final MetaActionType... actionTypes) {
        for (int i = 0; i < actionTypes.length; i++) {
            final MetaActionType actionType = actionTypes[i];
            if (typeSet.contains(actionType)) {
                return false;
            }
        }
        return true;
    }

    private boolean typeIsAnd(final MetaActionType... actionType) {
        final List<MetaActionType> list = Arrays.asList(actionType);
        return typeSet.containsAll(list);
    }

    private boolean typeIsOr(MetaActionType... actionTypes) {
        for (int i = 0; i < actionTypes.length; i++) {
            final MetaActionType actionType = actionTypes[i];
            if (true == typeSet.contains(actionType)) {
                return true;
            }
        }
        return false;
    }

    private static Method extractDisableMethod(final Method method, final Class entityClass) {
        return ReflectionUtils.extractDependantContextMethod("disable", method, entityClass);
    }

    private static Method extractHideMethod(final Method method, final Class entityClass) {
        return ReflectionUtils.extractDependantContextMethod("hide", method, entityClass);
    }
}
